using System;
using System.Collections.Specialized;
using System.Collections.Generic;
using System.Text;
using System.Web;
using System.Web.Security;
using System.Web.UI;
using System.Web.UI.WebControls;
using System.Reflection;
using BizElements.BusinessLayer;

namespace BizElements.Web
{
    /// <summary>
    /// Registers client-side scripts.
    /// </summary>
    /// <remarks>Supports both "classic" and AJAX script managers.</remarks>
    public static class JScript
    {
        #region Private methods and properties.

        private static string GetUniqueScriptKey(string keyPrefix)
        {
            return keyPrefix + "_" + Guid.NewGuid().ToString();
        }

        private static Page Page
        {
            get
            { 
                Page page = HttpContext.Current.Handler as Page;
                if (page == null)
                    throw new Exception("HttpContext.Current.Handler is not an instance of System.Web.UI.Page.");

                return page;
            }
        }

        #endregion

        #region RegisterStartupScript.

        /// <summary>
        /// Registers the script with a unique key which is executed when the page finishes loading or when an asynchronous postback occurs.
        /// </summary>
        /// <param name="script">The startup script literal to register.</param>
        /// <param name="addScriptTags">A Boolean value indicating whether to add script tags.</param>
        public static void RegisterStartupScript(string script, bool addScriptTags)
        {
            RegisterStartupScript(GetUniqueScriptKey("JS"), script, addScriptTags);
        }

        /// <summary>
        /// Registers the script which is executed when the page finishes loading or when an asynchronous postback occurs.
        /// </summary>
        /// <param name="key">The key of the startup script to register.</param>
        /// <param name="script">The startup script literal to register.</param>
        /// <param name="addScriptTags">A Boolean value indicating whether to add script tags.</param>
        public static void RegisterStartupScript(string key, string script, bool addScriptTags)
        {
            Page currPage = JScript.Page;
            ScriptManager ajaxManager = ScriptManager.GetCurrent(currPage);
            bool isAsyncPostBack = (ajaxManager != null) && (ajaxManager.IsInAsyncPostBack);
            if (isAsyncPostBack)
                ScriptManager.RegisterStartupScript(currPage, typeof(string), key, script, addScriptTags);
            else
                currPage.ClientScript.RegisterStartupScript(typeof(string), key, script, addScriptTags);
        }

        #endregion

        #region RegisterClientScriptResource.

        /// <summary>
        /// Registers the client script resource with AJAX ScriptManager or classic ClientScriptManager if the page is not AJAX enabled.
        /// </summary>
        /// <param name="type">The type of the client script resource to register.</param>
        /// <param name="resourceName">The name of the client script resource to register.</param>
        public static void RegisterClientScriptResource(Type type, string resourceName)
        {
            Page currPage = JScript.Page;
            ScriptManager ajaxManager = ScriptManager.GetCurrent(currPage);
            bool isAsyncPostBack = (ajaxManager != null) && (ajaxManager.IsInAsyncPostBack);
            if (isAsyncPostBack)
                ScriptManager.RegisterClientScriptResource(currPage, type, resourceName);
            else
                currPage.ClientScript.RegisterClientScriptResource(type, resourceName);
        }

        #endregion

        #region RegisterClientScriptBlock.

        /// <summary>
        /// Registers the client script with AJAX ScriptManager or classic ClientScriptManager if the page is not AJAX enabled and assings it a unique key.
        /// </summary>
        /// <param name="script">The startup script literal to register.</param>
        /// <param name="addScriptTags">A Boolean value indicating whether to add script tags.</param>
        public static void RegisterClientScriptBlock(string script, bool addScriptTags)
        {
            RegisterClientScriptBlock(GetUniqueScriptKey("JS"), script, addScriptTags);
        }

        /// <summary>
        /// Registers the client script with AJAX ScriptManager or classic ClientScriptManager if the page is not AJAX enabled.
        /// </summary>
        /// <param name="key">The key of the startup script to register.</param>
        /// <param name="script">The startup script literal to register.</param>
        /// <param name="addScriptTags">A Boolean value indicating whether to add script tags.</param>
        public static void RegisterClientScriptBlock(string key, string script, bool addScriptTags)
        {
            Page currPage = JScript.Page;
            ScriptManager ajaxManager = ScriptManager.GetCurrent(currPage);
            bool isAsyncPostBack = (ajaxManager != null) && (ajaxManager.IsInAsyncPostBack);
            if (isAsyncPostBack)
                ScriptManager.RegisterClientScriptBlock(currPage, typeof(string), key, script, addScriptTags);
            else
                currPage.ClientScript.RegisterClientScriptBlock(typeof(string), key, script, addScriptTags);
        }

        #endregion

        #region CleanString.

        /// <summary>
        /// Cleans string so that it can be safely used as JavaScript string constant.
        /// </summary>
        /// <param name="str">Input string.</param>
        /// <returns>JavaScript string constant.</returns>
        public static string CleanString(string str)
        {
            // UrlEncodeUnicode converts blanks to plus characters and unescape function doesn't convert them back to 
            // blanks. No issues with plus characters in the original string because they are converted to unicode representation.
            if (str == null)
                str = "";

            string cleanString = HttpUtility.UrlEncodeUnicode(str);
            cleanString = str.Replace('+', ' ');
            return cleanString;
        }

        #endregion

        #region Alert.

        /// <summary>
        /// Displays a dialog box containing an application-defined message.
        /// </summary>
        /// <param name="message">String that specifies the message to display in the dialog box.</param>
        public static void Alert(string message)
        {
            string jscript = RenderAlert(message);
            RegisterStartupScript(jscript, true);
        }

        /// <summary>
        /// Renders script which displays a dialog box containing an application-defined message.
        /// </summary>
        /// <param name="message">String that specifies the message to display in the dialog box.</param>
        /// <returns>Script body.</returns>
        public static string RenderAlert(string message)
        {
            string jscript = "window.alert(unescape(\"" + CleanString(message) + "\")); ";
            return jscript;
        }

        #endregion

        #region CloseWindow.

        /// <summary>
        /// Closes the current browser window.
        /// </summary>
        public static void CloseWindow()
        {
            string script = RenderCloseWindow();
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which closes the current browser window.
        /// </summary>
        /// <returns>Script body.</returns>
        public static string RenderCloseWindow()
        {
            string script = "window.close(); ";
            return script;
        }

        #endregion

        #region Confirm.

        /// <summary>
        /// Displays a confirmation dialog box for the specified client-side script.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="codeToExecuteIfConfirmed">JavaScript code which is executed if a user positively answers the given question.</param>
        public static void Confirm(string question, string codeToExecuteIfConfirmed)
        {
            string script = RenderConfirm(question, codeToExecuteIfConfirmed);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which displays a confirmation dialog box for the specified client-side script.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="codeToExecuteIfConfirmed">JavaScript code which is executed if a user positively answers the given question.</param>
        /// <returns>Script body.</returns>
        public static string RenderConfirm(string question, string codeToExecuteIfConfirmed)
        {
            codeToExecuteIfConfirmed = codeToExecuteIfConfirmed.Trim();
            if (codeToExecuteIfConfirmed.EndsWith(";") == false)
                codeToExecuteIfConfirmed += ";";

            string script = "if (window.confirm('" + CleanString(question) + "')) {" + codeToExecuteIfConfirmed + "}";
            return script;
        }

        /// <summary>
        /// Displays a confirmation dialog box for the specified client-side script.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="codeToExecuteIfConfirmed">JavaScript code which is executed if a user positively answers the given question.</param>
        /// <param name="codeToExecuteIfNotConfirmed">JavaScript code which is executed if a user negatively answers the given question.</param>
        public static void Confirm(string question, string codeToExecuteIfConfirmed, string codeToExecuteIfNotConfirmed)
        {
            string script = RenderConfirm(question, codeToExecuteIfConfirmed, codeToExecuteIfNotConfirmed);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which displays a confirmation dialog box for the specified client-side script.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="codeToExecuteIfConfirmed">JavaScript code which is executed if a user positively answers the given question.</param>
        /// <param name="codeToExecuteIfNotConfirmed">JavaScript code which is executed if a user negatively answers the given question.</param>
        /// <returns>Script body.</returns>
        public static string RenderConfirm(string question, string codeToExecuteIfConfirmed, string codeToExecuteIfNotConfirmed)
        {
            codeToExecuteIfConfirmed = codeToExecuteIfConfirmed.Trim();
            if (codeToExecuteIfConfirmed.EndsWith(";") == false)
                codeToExecuteIfConfirmed += ";";
            codeToExecuteIfNotConfirmed = codeToExecuteIfNotConfirmed.Trim();
            if (codeToExecuteIfNotConfirmed.EndsWith(";") == false)
                codeToExecuteIfNotConfirmed += ";";

            string script = "if (window.confirm('" + CleanString(question) + "')) {";
            script += codeToExecuteIfConfirmed;
            script += "} else {";
            script += codeToExecuteIfNotConfirmed;
            script += "}";
            return script;
        }

        #endregion

        #region Focus.

        /// <summary>
        /// Causes the element to receive the focus and executes the code specified by the <b>onfocus</b> event.
        /// </summary>
        /// <param name="controlToFocus">Control to focus.</param>
        public static void Focus(Control controlToFocus)
        {
            ScriptManager ajaxManager = ScriptManager.GetCurrent(Page);
            if (ajaxManager != null)
                ajaxManager.SetFocus(controlToFocus);
            else
                controlToFocus.Focus();
        }

        /// <summary>
        /// Causes the element to receive the focus and executes the code specified by the <b>onfocus</b> event.
        /// </summary>
        /// <param name="delayInMs">Delay in milliseconds.</param>
        /// <param name="htmlElementIdToFocus">ID of the HTML element to focus.</param>
        public static void Focus(string htmlElementIdToFocus, int delayInMs)
        {
            string script = RenderFocus(htmlElementIdToFocus, delayInMs);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Causes the element to receive the focus and executes the code specified by the <b>onfocus</b> event.
        /// </summary>
        /// <param name="htmlElementIdToFocus">ID of the HTML element to focus.</param>
        public static void Focus(string htmlElementIdToFocus)
        {
            string script = RenderFocus(htmlElementIdToFocus);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which causes the element to receive the focus and executes the code specified by the <b>onfocus</b> event.
        /// </summary>
        /// <param name="htmlElementIdToFocus">ID of the HTML element to focus.</param>
        /// <returns>Script body.</returns>
        public static string RenderFocus(string htmlElementIdToFocus)
        {
            string script = "if (document.getElementById('" + htmlElementIdToFocus + "') != null) ";
            script += "document.getElementById('" + htmlElementIdToFocus + "').focus(); ";
            return script;
        }

        /// <summary>
        /// Renders script which causes the element to receive the focus and executes the code specified by the <b>onfocus</b> event.
        /// </summary>
        /// <param name="htmlElementIdToFocus">ID of the HTML element to focus.</param>
        /// <param name="delayInMs">Delay in milliseconds.</param>
        /// <returns>Script body.</returns>
        public static string RenderFocus(string htmlElementIdToFocus, int delayInMs)
        {
            string script = "if (document.getElementById('" + htmlElementIdToFocus + "') != null) ";
            string focus = "document.getElementById('" + htmlElementIdToFocus + "').focus(); ";
            string setTimeout = "setTimeout(function(){" + focus + "}, " + delayInMs.ToString() + "); ";
            script += setTimeout;
            return script;
        }

        #endregion

        #region OpenWindow.

        /// <summary>
        /// Opens a new window and loads the document specified by a given URL.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        public static void OpenWindow(string url, int width, int height, int top, int left, bool allowScrollbars)
        {
            string script = RenderOpenWindow(url, width, height, top, left, allowScrollbars);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which opens a new window and loads the document specified by a given URL.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        /// <returns>Script body.</returns>
        public static string RenderOpenWindow(string url, int width, int height, int top, int left, bool allowScrollbars)
        {
            string scrollbars = (allowScrollbars) ? "yes" : "no";
            string script = "window.open('" + url + "', '', 'width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",scrollbars=" + scrollbars + ",status=no,resizable=yes'); ";
            return script;
        }

        /// <summary>
        /// Opens a new named window and loads the document specified by a given URL.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="windowName">String that specifies the name of the window. This name is used as the value 
        /// for the <b>TARGET</b> attribute on a form or an <b>a</b> element.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        public static void OpenWindow(string url, string windowName, int width, int height, int top, int left, bool allowScrollbars)
        {
            string script = RenderOpenWindow(url, windowName, width, height, top, left, allowScrollbars);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which opens a new named window and loads the document specified by a given URL.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="windowName">String that specifies the name of the window. This name is used as the value 
        /// for the <b>TARGET</b> attribute on a form or an <b>a</b> element.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        /// <returns>Script body.</returns>
        public static string RenderOpenWindow(string url, string windowName, int width, int height, int top, int left, bool allowScrollbars)
        {
            string scrollbars = (allowScrollbars) ? "yes" : "no";
            windowName = (windowName != null) ? windowName : "";
            string script = "window.open('" + url + "', '" + windowName + "', 'width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",scrollbars=" + scrollbars + ",status=no,resizable=yes'); ";
            return script;
        }

        /// <summary>
        /// Opens a new named window, centers it and loads the document specified by a given URL.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="windowName">String that specifies the name of the window. This name is used as the value 
        /// for the <b>TARGET</b> attribute on a form or an <b>a</b> element.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        public static void OpenWindow(string url, string windowName, int width, int height, bool allowScrollbars)
        {
            string script = RenderOpenWindow(url, windowName, width, height, allowScrollbars);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which opens a new named window, centers it and loads the document specified by a given URL.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="windowName">String that specifies the name of the window. This name is used as the value 
        /// for the <b>TARGET</b> attribute on a form or an <b>a</b> element.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        /// <returns>Script body.</returns>
        public static string RenderOpenWindow(string url, string windowName, int width, int height, bool allowScrollbars)
        {
            string scrollbars = (allowScrollbars) ? "yes" : "no";
            windowName = (windowName != null) ? windowName : "";
            string topCompute = string.Format("(screen.height/2 - {0})", height/2);
            string leftCompute = string.Format("(screen.width/2 - {0})", width/2);
            string script = "window.open('" + url + "', '" + windowName + "', 'width=" + width + ",height=" + height + ",top=' + " + topCompute + " + ',left=' + " + leftCompute + " + ',scrollbars=" + scrollbars + ",status=no,resizable=yes'); ";
            return script;
        }

        #endregion

        #region ShowModalDialog.

        const string jsShowModalDialog = "window.showModalDialog('{0}', '', 'dialogHeight: {1}px; dialogWidth: {2}px; dialogTop: {3}px; dialogLeft: {4}px; edge: Raised; center: No; help: Yes; resizable: Yes; status: Yes;'); ";
        const string jsShowCenteredModalDialog = "window.showModalDialog('{0}', '', 'dialogHeight: {1}px; dialogWidth: {2}px; edge: Raised; center: Yes; help: Yes; resizable: Yes; status: Yes;'); ";

        /// <summary>
        /// Opens a document in a modal dialog box for supported browsers or plain popup window for other browsers.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="centered">Specifies whether to center the dialog window within the desktop.</param>
        /// <remarks><para>Opens a new window with <b>window.showModalDialog()</b> function. The method automatically detects 
        /// if a browser supports modal dialogs. If it doesn't, the <b>window.open()</b> function is used.</para>
        /// <para>Currently modal dialogs are supported only for Internet Explorer. 
        /// Plain popup windows are used for all other browsers.</para></remarks>
        public static void ShowModalDialog(string url, int width, int height, int top, int left, bool centered)
        {
            string script = RenderShowModalDialog(url, width, height, top, left, centered);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which opens a document in a modal dialog box for supported browsers or plain popup window for other browsers.
        /// </summary>
        /// <param name="url">String that specifies the URL of the document to display.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="centered">Specifies whether to center the dialog window within the desktop.</param>
        /// <remarks><para>Opens a new window with <b>window.showModalDialog()</b> function. The method automatically detects 
        /// if a browser supports modal dialogs. If it doesn't, the <b>window.open()</b> function is used.</para>
        /// <para>Currently modal dialogs are supported only for Internet Explorer. 
        /// Plain popup windows are used for all other browsers.</para></remarks>
        /// <returns>Script body.</returns>
        public static string RenderShowModalDialog(string url, int width, int height, int top, int left, bool centered)
        {
            string script;
            bool isInternetExplorer = Page.Request.Browser.IsBrowser("IE");
            if (isInternetExplorer)
            {
                if (centered)
                    script = string.Format(jsShowCenteredModalDialog, url, height, width);
                else
                    script = string.Format(jsShowModalDialog, url, height, width, top, left);
            }
            else
            {
                script = RenderOpenWindow(url, width, height, top, left, true);
            }

            return script;
        }

        #endregion

        #region OpenWindowIfConfirmed.

        /// <summary>
        /// Opens a new window and loads the document specified by the given URL if a user positively answers the given question.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="urlToOpenIfConfirmed">URL which is openned if a user positively answers the given question.</param>
        /// <param name="windowName">String that specifies the name of the window. This name is used as the value 
        /// for the <b>TARGET</b> attribute on a form or an <b>a</b> element.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        public static void OpenWindowIfConfirmed(string question, string urlToOpenIfConfirmed, string windowName, int width, int height, int top, int left, bool allowScrollbars)
        {
            string script = RenderOpenWindowIfConfirmed(question, urlToOpenIfConfirmed, windowName, width, height, top, left, allowScrollbars);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which opens a new window and loads the document specified by the given URL if a user positively answers the given question.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="urlToOpenIfConfirmed">URL which is openned if a user positively answers the given question.</param>
        /// <param name="windowName">String that specifies the name of the window. This name is used as the value 
        /// for the <b>TARGET</b> attribute on a form or an <b>a</b> element.</param>
        /// <param name="width">The width of the window, in pixels. The minimum value is 100.</param>
        /// <param name="height">The height of the window, in pixels. The minimum value is 100.</param>
        /// <param name="top">Specifies the top position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0.</param>
        /// <param name="left">Specifies the left position, in pixels. This value is relative to the upper-left 
        /// corner of the screen. The value must be greater than or equal to 0. </param>
        /// <param name="allowScrollbars">Specifies whether to display horizontal and vertical scroll bars.</param>
        /// <returns>Script body.</returns>
        public static string RenderOpenWindowIfConfirmed(string question, string urlToOpenIfConfirmed, string windowName, int width, int height, int top, int left, bool allowScrollbars)
        {
            string scrollbars = (allowScrollbars) ? "yes" : "no";
            windowName = (windowName != null) ? windowName : "";
            string script = "if (window.confirm('" + CleanString(question) + "'))";
            script += " window.open('" + urlToOpenIfConfirmed + "', '" + windowName + "', 'width=" + width + ",height=" + height + ",top=" + top + ",left=" + left + ",scrollbars=" + scrollbars + ",status=no,resizable=yes'); ";
            return script;
        }

        #endregion

        #region RedirectIfConfirmed.

        /// <summary>
        /// Redirects a client to the given URL if a user positively answers the given question.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="urlToOpenIfConfirmed">URL which is openned if a user positively answers the given question.</param>
        public static void RedirectIfConfirmed(string question, string urlToOpenIfConfirmed)
        {
            string script = RenderRedirectIfConfirmed(question, urlToOpenIfConfirmed);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Renders script which redirects a client to the given URL if a user positively answers the given question.
        /// </summary>
        /// <param name="question">The question to display in the confirmation dialog box.</param>
        /// <param name="urlToOpenIfConfirmed">URL which is openned if a user positively answers the given question.</param>
        /// <returns>Script body.</returns>
        public static string RenderRedirectIfConfirmed(string question, string urlToOpenIfConfirmed)
        {
            string script = "if (window.confirm('" + CleanString(question) + "'))";
            script += "document.location = '" + urlToOpenIfConfirmed + "'; ";
            return script;
        }

        #endregion

        #region RegisterCssClass.

        /// <summary>
        /// Registers a CSS class at the end of the <b>head</b> element.
        /// </summary>
        /// <param name="className">Class name.</param>
        /// <param name="classBody">Class body. Style.</param>
        public static void RegisterCssClass(string className, string classBody)
        {
            if (!className.StartsWith("."))
                className = "." + className;

            if (IsCssClassRegistered(className))
                return;

            FreeStyle style = new FreeStyle();
            string[] keyValuePairs = classBody.Split(';');
            foreach (string keyAndValue in keyValuePairs)
            {
                string[] components = keyAndValue.Split(':');
                string key = components[0];
                string value = (components.Length > 1) ? components[1] : "";
                style.CssAttributes[key] = value;
            }            

            Page page = (Page)HttpContext.Current.Handler;
            page.Header.StyleSheet.CreateStyleRule(style, page.Header, className);

            Dictionary<string, string> tracer = GetCssClassTracer();
            tracer.Add(className, null);
        }

        private static bool IsCssClassRegistered(string className)
        {
            Dictionary<string, string> tracer = GetCssClassTracer();
            return tracer.ContainsKey(className);
        }

        const string cssClassTracerItemKey = "Biz.Enterprise.JScript.CssClassTracer";

        private static Dictionary<string, string> GetCssClassTracer()
        {
            Page page = (Page)HttpContext.Current.Handler;
            Dictionary<string, string> tracer = page.Items[cssClassTracerItemKey] as Dictionary<string, string>;
            if (tracer == null)
            {
                tracer = new Dictionary<string, string>();
                page.Items.Add(cssClassTracerItemKey, tracer);
            }

            return tracer;
        }

        private class FreeStyle : Style
        {
            Dictionary<string, string> cssAttributes = new Dictionary<string, string>();

            public Dictionary<string, string> CssAttributes
            {
                get { return this.cssAttributes; }
            }

            protected override void FillStyleAttributes(CssStyleCollection attributes, IUrlResolutionService urlResolver)
            {
                base.FillStyleAttributes(attributes, urlResolver);
                foreach (KeyValuePair<string, string> keyAndValue in this.CssAttributes)
                    attributes[keyAndValue.Key] = keyAndValue.Value;
            }
        }

        #endregion

        #region Click.

        /// <summary>
        /// Raises a client-side click event for the control if it exists.
        /// </summary>
        /// <param name="ctl">Target control.</param>
        public static void Click(Control ctl)
        {
            string script = RenderClick(ctl);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Raises a client-side click event for the control.
        /// </summary>
        /// <param name="ctl">Target control.</param>
        /// <param name="checkThatElementExists">Whether the generated script should first that the target element exists.</param>
        public static void Click(Control ctl, bool checkThatElementExists)
        {
            string script = RenderClick(ctl, checkThatElementExists);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Raises a client-side click event for the HTML element if it exists.
        /// </summary>
        /// <param name="elementId">Target element ID.</param>
        public static void Click(string elementId)
        {
            string script = RenderClick(elementId);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Raises a client-side click event for the HTML element.
        /// </summary>
        /// <param name="elementId">Target element ID.</param>
        /// <param name="checkThatElementExists">Whether the generated script should first that the target element exists.</param>
        public static void Click(string elementId, bool checkThatElementExists)
        {
            string script = RenderClick(elementId, checkThatElementExists);
            RegisterStartupScript(script, true);
        }

        /// <summary>
        /// Rendres script which raises a client-side click event for the control if it exists.
        /// </summary>
        /// <param name="ctl">Target control.</param>
        /// <returns>Script body.</returns>
        public static string RenderClick(Control ctl)
        {
            string elementId = ctl.ClientID ?? ctl.ID;
            return RenderClick(elementId);
        }

        /// <summary>
        /// Rendres script which raises a client-side click event for the control.
        /// </summary>
        /// <param name="ctl">Target control.</param>
        /// <param name="checkThatElementExists">Whether the generated script should first that the target element exists.</param>
        /// <returns>Script body.</returns>
        public static string RenderClick(Control ctl, bool checkThatElementExists)
        {
            string elementId = ctl.ClientID ?? ctl.ID;
            return RenderClick(elementId, checkThatElementExists);
        }

        /// <summary>
        /// Rendres script which raises a client-side click event for the HTML element if it exists.
        /// </summary>
        /// <param name="elementId">Target element ID.</param>
        /// <returns>Script body.</returns>
        public static string RenderClick(string elementId)
        {
            const string jsClickElement = "if (document.getElementById(\"{0}\") != null) document.getElementById(\"{0}\").click(); ";
            return string.Format(jsClickElement, elementId);
        }

        /// <summary>
        /// Rendres script which raises a client-side click event for the HTML element.
        /// </summary>
        /// <param name="elementId">Target element ID.</param>
        /// <param name="checkThatElementExists">Whether the generated script should first that the target element exists.</param>
        /// <returns>Script body.</returns>
        public static string RenderClick(string elementId, bool checkThatElementExists)
        {
            const string jsClickElement = "if (document.getElementById(\"{0}\") != null) document.getElementById(\"{0}\").click(); ";
            const string jsUnsafeClickElement = "document.getElementById(\"{0}\").click(); ";
            if (checkThatElementExists)
                return string.Format(jsClickElement, elementId);
            else
                return string.Format(jsUnsafeClickElement, elementId);
        }

        #endregion

        internal static bool IsInternetExplorer()
        {
            return Page.Request.Browser.IsBrowser("IE");
        }
    }
}